home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / rmtlib2 < prev    next >
Encoding:
Internet Message Format  |  1989-04-19  |  24.9 KB

  1. Subject:  v18i109:  Remote tape library
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: arnold@emoryu1.cc.emory.edu (Arnold D. Robbins)
  7. Posting-number: Volume 18, Issue 109
  8. Archive-name: rmtlib2
  9.  
  10. [  Needs for for non-BSD-dervied systems.   --r$  ]
  11.  
  12. This is the remote mag tape library. It allows a program that uses
  13. Unix system calls to transparently use a file (usually a tape drive) on
  14. another system via /etc/rmt, simply by including <rmt.h>.  It is
  15. particularly useful with tar and dd, and is supplied with GNU tar.
  16.  
  17. This package has evolved somewhat over the years.  My thanks to the
  18. people who did most of the original work, and those who've contributed
  19. bug fixes; appropriate credit is in the man page and source files.
  20.  
  21. Enjoy,
  22.  
  23. Arnold Robbins
  24. Emory U. Computing Center
  25. arnold@emoryu1.cc.emory.edu
  26. gatech!emoryu1!arnold
  27.  
  28. ----------------------------------------
  29. #! /bin/sh
  30. # This is a shell archive, meaning:
  31. # 1. Remove everything above the #! /bin/sh line.
  32. # 2. Save the resulting text in a file.
  33. # 3. Execute the file with /bin/sh (not csh) to create:
  34. #    README
  35. #    Makefile
  36. #    rmt.h
  37. #    rmtlib.c
  38. #    rmtops.3
  39. export PATH; PATH=/bin:/usr/bin:$PATH
  40. echo shar: "extracting 'README'" '(602 characters)'
  41. if test -f 'README'
  42. then
  43.     echo shar: "will not over-write existing file 'README'"
  44. else
  45. cat << \SHAR_EOF > 'README'
  46. README
  47.  
  48. This is the remote mag tape library. It allows a program that uses
  49. Unix system calls to transparently use a file (usually a tape drive) on
  50. another system via /etc/rmt, simply by including <rmt.h>.  It is
  51. particularly useful with tar and dd, and is supplied with GNU tar.
  52.  
  53. This package has evolved somewhat over the years.  My thanks to the
  54. people who did most of the original work, and those who've contributed
  55. bug fixes; appropriate credit is in the man page and source files.
  56.  
  57. Enjoy,
  58.  
  59. Arnold Robbins
  60. Emory U. Computing Center
  61. arnold@emoryu1.cc.emory.edu
  62. gatech!emoryu1!arnold
  63. +1 404 727 7636
  64. SHAR_EOF
  65. fi
  66. echo shar: "extracting 'Makefile'" '(421 characters)'
  67. if test -f 'Makefile'
  68. then
  69.     echo shar: "will not over-write existing file 'Makefile'"
  70. else
  71. cat << \SHAR_EOF > 'Makefile'
  72. #
  73. # $Header: Makefile,v 1.1 86/10/09 16:42:13 root Locked $
  74. #
  75. # $Log:    Makefile,v $
  76. # Revision 1.1  86/10/09  16:42:13  root
  77. # Initial revision
  78. #
  79. # Makefile for rmtlib
  80.  
  81. CFLAGS= -O
  82. SRC= rmtlib.c
  83. DOC= rmtops.3
  84.  
  85. MANSEC=3
  86. DEST= /usr/lib
  87.  
  88. librmt.a: rmtlib.o
  89.     ar rv librmt.a rmtlib.o
  90.  
  91. install: librmt.a
  92.     cp librmt.a /usr/lib
  93.     ranlib /usr/lib/librmt.a
  94.     cp $(DOC) /usr/man/man$(MANSEC)/rmtops.$(MANSEC)
  95.  
  96. clean:
  97.     rm -f rmtlib.o
  98. SHAR_EOF
  99. fi
  100. echo shar: "extracting 'rmt.h'" '(1056 characters)'
  101. if test -f 'rmt.h'
  102. then
  103.     echo shar: "will not over-write existing file 'rmt.h'"
  104. else
  105. cat << \SHAR_EOF > 'rmt.h'
  106. /*
  107.  * $Header: rmt.h,v 1.1 86/10/09 16:17:20 root Locked $
  108.  *
  109.  * $Log:    rmt.h,v $
  110.  * Revision 1.1  86/10/09  16:17:20  root
  111.  * Initial revision
  112.  * 
  113.  */
  114.  
  115. /*
  116.  *    rmt.h
  117.  *
  118.  *    Added routines to replace open(), close(), lseek(), ioctl(), etc.
  119.  *    The preprocessor can be used to remap these the rmtopen(), etc
  120.  *    thus minimizing source changes.
  121.  *
  122.  *    This file must be included before <sys/stat.h>, since it redefines
  123.  *    stat to be rmtstat, so that struct stat xyzzy; declarations work
  124.  *    properly.
  125.  *
  126.  *    -- Fred Fish (w/some changes by Arnold Robbins)
  127.  */
  128.  
  129.  
  130. #ifndef access        /* avoid multiple redefinition */
  131. #ifndef lint        /* in this case what lint doesn't know won't hurt it */
  132. #define access rmtaccess
  133. #define close rmtclose
  134. #define creat rmtcreat
  135. #define dup rmtdup
  136. #define fcntl rmtfcntl
  137. #define fstat rmtfstat
  138. #define ioctl rmtioctl
  139. #define isatty rmtisatty
  140. #define lseek rmtlseek
  141. #define lstat rmtlstat
  142. #define open rmtopen
  143. #define read rmtread
  144. #define stat rmtstat
  145. #define write rmtwrite
  146.  
  147. extern long rmtlseek ();    /* all the rest are int's */
  148. #endif
  149. #endif
  150. SHAR_EOF
  151. fi
  152. echo shar: "extracting 'rmtlib.c'" '(16015 characters)'
  153. if test -f 'rmtlib.c'
  154. then
  155.     echo shar: "will not over-write existing file 'rmtlib.c'"
  156. else
  157. cat << \SHAR_EOF > 'rmtlib.c'
  158. #ifndef lint
  159. static char *RCSid = "$Header: /usr/src/local/usr.lib/librmt/RCS/rmtlib.c,v 1.7 89/03/23 14:09:51 root Exp Locker: root $";
  160. #endif
  161.  
  162. /*
  163.  * $Log:    rmtlib.c,v $
  164.  * Revision 1.7  89/03/23  14:09:51  root
  165.  * Fix from haynes@ucscc.ucsc.edu for use w/compat. ADR.
  166.  * 
  167.  * Revision 1.6  88/10/25  17:04:29  root
  168.  * rexec code and a bug fix from srs!dan, miscellanious cleanup. ADR.
  169.  * 
  170.  * Revision 1.5  88/10/25  16:30:17  root
  171.  * Fix from jeff@gatech.edu for getting user@host:dev right. ADR.
  172.  * 
  173.  * Revision 1.4  87/10/30  10:36:12  root
  174.  * Made 4.2 syntax a compile time option. ADR.
  175.  * 
  176.  * Revision 1.3  87/04/22  11:16:48  root
  177.  * Two fixes from parmelee@wayback.cs.cornell.edu to correctly
  178.  * do fd biasing and rmt protocol on 'S' command. ADR.
  179.  * 
  180.  * Revision 1.2  86/10/09  16:38:53  root
  181.  * Changed to reflect 4.3BSD rcp syntax. ADR.
  182.  * 
  183.  * Revision 1.1  86/10/09  16:17:35  root
  184.  * Initial revision
  185.  * 
  186.  */
  187.  
  188. /*
  189.  *    rmt --- remote tape emulator subroutines
  190.  *
  191.  *    Originally written by Jeff Lee, modified some by Arnold Robbins
  192.  *
  193.  *    WARNING:  The man page rmt(8) for /etc/rmt documents the remote mag
  194.  *    tape protocol which rdump and rrestore use.  Unfortunately, the man
  195.  *    page is *WRONG*.  The author of the routines I'm including originally
  196.  *    wrote his code just based on the man page, and it didn't work, so he
  197.  *    went to the rdump source to figure out why.  The only thing he had to
  198.  *    change was to check for the 'F' return code in addition to the 'E',
  199.  *    and to separate the various arguments with \n instead of a space.  I
  200.  *    personally don't think that this is much of a problem, but I wanted to
  201.  *    point it out.
  202.  *    -- Arnold Robbins
  203.  *
  204.  *    Redone as a library that can replace open, read, write, etc, by
  205.  *    Fred Fish, with some additional work by Arnold Robbins.
  206.  */
  207.  
  208. /*
  209.  *    MAXUNIT --- Maximum number of remote tape file units
  210.  *
  211.  *    READ --- Return the number of the read side file descriptor
  212.  *    WRITE --- Return the number of the write side file descriptor
  213.  */
  214.  
  215. #define RMTIOCTL    1
  216. /* #define USE_REXEC    1    /* rexec code courtesy of Dan Kegel, srs!dan */
  217.  
  218. #include <stdio.h>
  219. #include <signal.h>
  220. #include <sys/types.h>
  221.  
  222. #ifdef RMTIOCTL
  223. #include <sys/ioctl.h>
  224. #include <sys/mtio.h>
  225. #endif
  226.  
  227. #ifdef USE_REXEC
  228. #include <netdb.h>
  229. #endif
  230.  
  231. #include <errno.h>
  232. #include <setjmp.h>
  233. #include <sys/stat.h>
  234.  
  235. #define BUFMAGIC    64    /* a magic number for buffer sizes */
  236. #define MAXUNIT    4
  237.  
  238. #define READ(fd)    (Ctp[fd][0])
  239. #define WRITE(fd)    (Ptc[fd][1])
  240.  
  241. static int Ctp[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  242. static int Ptc[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  243.  
  244. static jmp_buf Jmpbuf;
  245. extern int errno;
  246.  
  247. /*
  248.  *    abort --- close off a remote tape connection
  249.  */
  250.  
  251. static void abort(fildes)
  252. int fildes;
  253. {
  254.     close(READ(fildes));
  255.     close(WRITE(fildes));
  256.     READ(fildes) = -1;
  257.     WRITE(fildes) = -1;
  258. }
  259.  
  260.  
  261.  
  262. /*
  263.  *    command --- attempt to perform a remote tape command
  264.  */
  265.  
  266. static int command(fildes, buf)
  267. int fildes;
  268. char *buf;
  269. {
  270.     register int blen;
  271.     int (*pstat)();
  272.  
  273. /*
  274.  *    save current pipe status and try to make the request
  275.  */
  276.  
  277.     blen = strlen(buf);
  278.     pstat = signal(SIGPIPE, SIG_IGN);
  279.     if (write(WRITE(fildes), buf, blen) == blen)
  280.     {
  281.         signal(SIGPIPE, pstat);
  282.         return(0);
  283.     }
  284.  
  285. /*
  286.  *    something went wrong. close down and go home
  287.  */
  288.  
  289.     signal(SIGPIPE, pstat);
  290.     abort(fildes);
  291.  
  292.     errno = EIO;
  293.     return(-1);
  294. }
  295.  
  296.  
  297.  
  298. /*
  299.  *    status --- retrieve the status from the pipe
  300.  */
  301.  
  302. static int status(fildes)
  303. int fildes;
  304. {
  305.     int i;
  306.     char c, *cp;
  307.     char buffer[BUFMAGIC];
  308.  
  309. /*
  310.  *    read the reply command line
  311.  */
  312.  
  313.     for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++)
  314.     {
  315.         if (read(READ(fildes), cp, 1) != 1)
  316.         {
  317.             abort(fildes);
  318.             errno = EIO;
  319.             return(-1);
  320.         }
  321.         if (*cp == '\n')
  322.         {
  323.             *cp = 0;
  324.             break;
  325.         }
  326.     }
  327.  
  328.     if (i == BUFMAGIC)
  329.     {
  330.         abort(fildes);
  331.         errno = EIO;
  332.         return(-1);
  333.     }
  334.  
  335. /*
  336.  *    check the return status
  337.  */
  338.  
  339.     for (cp = buffer; *cp; cp++)
  340.         if (*cp != ' ')
  341.             break;
  342.  
  343.     if (*cp == 'E' || *cp == 'F')
  344.     {
  345.         errno = atoi(cp + 1);
  346.         while (read(READ(fildes), &c, 1) == 1)
  347.             if (c == '\n')
  348.                 break;
  349.  
  350.         if (*cp == 'F')
  351.             abort(fildes);
  352.  
  353.         return(-1);
  354.     }
  355.  
  356. /*
  357.  *    check for mis-synced pipes
  358.  */
  359.  
  360.     if (*cp != 'A')
  361.     {
  362.         abort(fildes);
  363.         errno = EIO;
  364.         return(-1);
  365.     }
  366.  
  367.     return(atoi(cp + 1));
  368. }
  369.  
  370. #ifdef USE_REXEC
  371.  
  372. /*
  373.  * _rmt_rexec
  374.  *
  375.  * execute /etc/rmt on a remote system using rexec().
  376.  * Return file descriptor of bidirectional socket for stdin and stdout
  377.  * If username is NULL, or an empty string, uses current username.
  378.  *
  379.  * ADR: By default, this code is not used, since it requires that
  380.  * the user have a .netrc file in his/her home directory, or that the
  381.  * application designer be willing to have rexec prompt for login and
  382.  * password info. This may be unacceptable, and .rhosts files for use
  383.  * with rsh are much more common on BSD systems.
  384.  */
  385.  
  386. static int
  387. _rmt_rexec(host, user)
  388. char *host;
  389. char *user;        /* may be NULL */
  390. {
  391.     struct servent *rexecserv;
  392.  
  393.     rexecserv = getservbyname("exec", "tcp");
  394.     if (NULL == rexecserv) {
  395.         fprintf (stderr, "? exec/tcp: service not available.");
  396.         exit (-1);
  397.     }
  398.     if ((user != NULL) && *user == '\0')
  399.         user = (char *) NULL;
  400.     return rexec (&host, rexecserv->s_port, user, NULL,
  401.             "/etc/rmt", (int *)NULL);
  402. }
  403. #endif /* USE_REXEC */
  404.  
  405. /*
  406.  *    _rmt_open --- open a magtape device on system specified, as given user
  407.  *
  408.  *    file name has the form [user@]system:/dev/????
  409. #ifdef COMPAT
  410.  *    file name has the form system[.user]:/dev/????
  411. #endif
  412.  */
  413.  
  414. #define MAXHOSTLEN    257    /* BSD allows very long host names... */
  415.  
  416. static int _rmt_open (path, oflag, mode)
  417. char *path;
  418. int oflag;
  419. int mode;
  420. {
  421.     int i, rc;
  422.     char buffer[BUFMAGIC];
  423.     char system[MAXHOSTLEN];
  424.     char device[BUFMAGIC];
  425.     char login[BUFMAGIC];
  426.     char *sys, *dev, *user;
  427.  
  428.     sys = system;
  429.     dev = device;
  430.     user = login;
  431.  
  432. /*
  433.  *    first, find an open pair of file descriptors
  434.  */
  435.  
  436.     for (i = 0; i < MAXUNIT; i++)
  437.         if (READ(i) == -1 && WRITE(i) == -1)
  438.             break;
  439.  
  440.     if (i == MAXUNIT)
  441.     {
  442.         errno = EMFILE;
  443.         return(-1);
  444.     }
  445.  
  446. /*
  447.  *    pull apart system and device, and optional user
  448.  *    don't munge original string
  449.  *    if COMPAT is defined, also handle old (4.2) style person.site notation.
  450.  */
  451.  
  452.     while (*path != '@'
  453. #ifdef COMPAT
  454.             && *path != '.'
  455. #endif
  456.             && *path != ':') {
  457.         *sys++ = *path++;
  458.     }
  459.     *sys = '\0';
  460.     path++;
  461.  
  462.     if (*(path - 1) == '@')
  463.     {
  464.         (void) strcpy (user, system);    /* saw user part of user@host */
  465.         sys = system;            /* start over */
  466.         while (*path != ':') {
  467.             *sys++ = *path++;
  468.         }
  469.         *sys = '\0';
  470.         path++;
  471.     }
  472. #ifdef COMPAT
  473.     else if (*(path - 1) == '.')
  474.     {
  475.         while (*path != ':') {
  476.             *user++ = *path++;
  477.         }
  478.         *user = '\0';
  479.         path++;
  480.     }
  481. #endif
  482.     else
  483.         *user = '\0';
  484.  
  485.     while (*path) {
  486.         *dev++ = *path++;
  487.     }
  488.     *dev = '\0';
  489.  
  490. #ifdef USE_REXEC
  491. /* 
  492.  *    Execute the remote command using rexec 
  493.  */
  494.     READ(i) = WRITE(i) = _rmt_rexec(system, login);
  495.     if (READ(i) < 0)
  496.         return -1;
  497. #else
  498. /*
  499.  *    setup the pipes for the 'rsh' command and fork
  500.  */
  501.  
  502.     if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
  503.         return(-1);
  504.  
  505.     if ((rc = fork()) == -1)
  506.         return(-1);
  507.  
  508.     if (rc == 0)
  509.     {
  510.         close(0);
  511.         dup(Ptc[i][0]);
  512.         close(Ptc[i][0]); close(Ptc[i][1]);
  513.         close(1);
  514.         dup(Ctp[i][1]);
  515.         close(Ctp[i][0]); close(Ctp[i][1]);
  516.         (void) setuid (getuid ());
  517.         (void) setgid (getgid ());
  518.         if (*login)
  519.         {
  520.             execl("/usr/ucb/rsh", "rsh", system, "-l", login,
  521.                 "/etc/rmt", (char *) 0);
  522.             execl("/usr/bin/remsh", "remsh", system, "-l", login,
  523.                 "/etc/rmt", (char *) 0);
  524.         }
  525.         else
  526.         {
  527.             execl("/usr/ucb/rsh", "rsh", system,
  528.                 "/etc/rmt", (char *) 0);
  529.             execl("/usr/bin/remsh", "remsh", system,
  530.                 "/etc/rmt", (char *) 0);
  531.         }
  532.  
  533. /*
  534.  *    bad problems if we get here
  535.  */
  536.  
  537.         perror("exec");
  538.         exit(1);
  539.     }
  540.  
  541.     close(Ptc[i][0]); close(Ctp[i][1]);
  542. #endif
  543.  
  544. /*
  545.  *    now attempt to open the tape device
  546.  */
  547.  
  548.     sprintf(buffer, "O%s\n%d\n", device, oflag);
  549.     if (command(i, buffer) == -1 || status(i) == -1)
  550.         return(-1);
  551.  
  552.     return(i);
  553. }
  554.  
  555.  
  556.  
  557. /*
  558.  *    _rmt_close --- close a remote magtape unit and shut down
  559.  */
  560.  
  561. static int _rmt_close(fildes)
  562. int fildes;
  563. {
  564.     int rc;
  565.  
  566.     if (command(fildes, "C\n") != -1)
  567.     {
  568.         rc = status(fildes);
  569.  
  570.         abort(fildes);
  571.         return(rc);
  572.     }
  573.  
  574.     return(-1);
  575. }
  576.  
  577.  
  578.  
  579. /*
  580.  *    _rmt_read --- read a buffer from a remote tape
  581.  */
  582.  
  583. static int _rmt_read(fildes, buf, nbyte)
  584. int fildes;
  585. char *buf;
  586. unsigned int nbyte;
  587. {
  588.     int rc, i;
  589.     char buffer[BUFMAGIC];
  590.  
  591.     sprintf(buffer, "R%d\n", nbyte);
  592.     if (command(fildes, buffer) == -1 || (rc = status(fildes)) == -1)
  593.         return(-1);
  594.  
  595.     for (i = 0; i < rc; i += nbyte, buf += nbyte)
  596.     {
  597.         nbyte = read(READ(fildes), buf, rc);
  598.         if (nbyte <= 0)
  599.         {
  600.             abort(fildes);
  601.             errno = EIO;
  602.             return(-1);
  603.         }
  604.     }
  605.  
  606.     return(rc);
  607. }
  608.  
  609.  
  610.  
  611. /*
  612.  *    _rmt_write --- write a buffer to the remote tape
  613.  */
  614.  
  615. static int _rmt_write(fildes, buf, nbyte)
  616. int fildes;
  617. char *buf;
  618. unsigned int nbyte;
  619. {
  620.     int rc;
  621.     char buffer[BUFMAGIC];
  622.     int (*pstat)();
  623.  
  624.     sprintf(buffer, "W%d\n", nbyte);
  625.     if (command(fildes, buffer) == -1)
  626.         return(-1);
  627.  
  628.     pstat = signal(SIGPIPE, SIG_IGN);
  629.     if (write(WRITE(fildes), buf, nbyte) == nbyte)
  630.     {
  631.         signal (SIGPIPE, pstat);
  632.         return(status(fildes));
  633.     }
  634.  
  635.     signal (SIGPIPE, pstat);
  636.     abort(fildes);
  637.     errno = EIO;
  638.     return(-1);
  639. }
  640.  
  641.  
  642.  
  643. /*
  644.  *    _rmt_lseek --- perform an imitation lseek operation remotely
  645.  */
  646.  
  647. static long _rmt_lseek(fildes, offset, whence)
  648. int fildes;
  649. long offset;
  650. int whence;
  651. {
  652.     char buffer[BUFMAGIC];
  653.  
  654.     sprintf(buffer, "L%d\n%d\n", offset, whence);
  655.     if (command(fildes, buffer) == -1)
  656.         return(-1);
  657.  
  658.     return(status(fildes));
  659. }
  660.  
  661.  
  662. /*
  663.  *    _rmt_ioctl --- perform raw tape operations remotely
  664.  */
  665.  
  666. #ifdef RMTIOCTL
  667. static _rmt_ioctl(fildes, op, arg)
  668. int fildes, op;
  669. char *arg;
  670. {
  671.     char c;
  672.     int rc, cnt;
  673.     char buffer[BUFMAGIC];
  674.  
  675. /*
  676.  *    MTIOCOP is the easy one. nothing is transfered in binary
  677.  */
  678.  
  679.     if (op == MTIOCTOP)
  680.     {
  681.         sprintf(buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
  682.             ((struct mtop *) arg)->mt_count);
  683.         if (command(fildes, buffer) == -1)
  684.             return(-1);
  685.         return(status(fildes));
  686.     }
  687.  
  688. /*
  689.  *    we can only handle 2 ops, if not the other one, punt
  690.  */
  691.  
  692.     if (op != MTIOCGET)
  693.     {
  694.         errno = EINVAL;
  695.         return(-1);
  696.     }
  697.  
  698. /*
  699.  *    grab the status and read it directly into the structure
  700.  *    this assumes that the status buffer is (hopefully) not
  701.  *    padded and that 2 shorts fit in a long without any word
  702.  *    alignment problems, ie - the whole struct is contiguous
  703.  *    NOTE - this is probably NOT a good assumption.
  704.  */
  705.  
  706.     if (command(fildes, "S") == -1 || (rc = status(fildes)) == -1)
  707.         return(-1);
  708.  
  709.     for (; rc > 0; rc -= cnt, arg += cnt)
  710.     {
  711.         cnt = read(READ(fildes), arg, rc);
  712.         if (cnt <= 0)
  713.         {
  714.             abort(fildes);
  715.             errno = EIO;
  716.             return(-1);
  717.         }
  718.     }
  719.  
  720. /*
  721.  *    now we check for byte position. mt_type is a small integer field
  722.  *    (normally) so we will check its magnitude. if it is larger than
  723.  *    256, we will assume that the bytes are swapped and go through
  724.  *    and reverse all the bytes
  725.  */
  726.  
  727.     if (((struct mtget *) arg)->mt_type < 256)
  728.         return(0);
  729.  
  730.     for (cnt = 0; cnt < rc; cnt += 2)
  731.     {
  732.         c = arg[cnt];
  733.         arg[cnt] = arg[cnt+1];
  734.         arg[cnt+1] = c;
  735.     }
  736.  
  737.     return(0);
  738.   }
  739. #endif /* RMTIOCTL */
  740.  
  741. /*
  742.  *    Added routines to replace open(), close(), lseek(), ioctl(), etc.
  743.  *    The preprocessor can be used to remap these the rmtopen(), etc
  744.  *    thus minimizing source changes:
  745.  *
  746.  *        #ifdef <something>
  747.  *        #  define access rmtaccess
  748.  *        #  define close rmtclose
  749.  *        #  define creat rmtcreat
  750.  *        #  define dup rmtdup
  751.  *        #  define fcntl rmtfcntl
  752.  *        #  define fstat rmtfstat
  753.  *        #  define ioctl rmtioctl
  754.  *        #  define isatty rmtisatty
  755.  *        #  define lseek rmtlseek
  756.  *        #  define lstat rmtlstat
  757.  *        #  define open rmtopen
  758.  *        #  define read rmtread
  759.  *        #  define stat rmtstat
  760.  *        #  define write rmtwrite
  761.  *        #endif
  762.  *
  763.  *    -- Fred Fish
  764.  *
  765.  *    ADR --- I set up a <rmt.h> include file for this
  766.  *
  767.  */
  768.  
  769. /*
  770.  *    Note that local vs remote file descriptors are distinquished
  771.  *    by adding a bias to the remote descriptors.  This is a quick
  772.  *    and dirty trick that may not be portable to some systems.
  773.  */
  774.  
  775. #define REM_BIAS 128
  776.  
  777.  
  778. /*
  779.  *    Test pathname to see if it is local or remote.  A remote device
  780.  *    is any string that contains ":/dev/".  Returns 1 if remote,
  781.  *    0 otherwise.
  782.  */
  783.  
  784. static int remdev (path)
  785. register char *path;
  786. {
  787. #define strchr    index
  788.     extern char *strchr ();
  789.  
  790.     if ((path = strchr (path, ':')) != NULL)
  791.     {
  792.         if (strncmp (path + 1, "/dev/", 5) == 0)
  793.         {
  794.             return (1);
  795.         }
  796.     }
  797.     return (0);
  798. }
  799.  
  800.  
  801. /*
  802.  *    Open a local or remote file.  Looks just like open(2) to
  803.  *    caller.
  804.  */
  805.  
  806. int rmtopen (path, oflag, mode)
  807. char *path;
  808. int oflag;
  809. int mode;
  810. {
  811.     int fd;
  812.  
  813.     if (remdev (path))
  814.     {
  815.         fd = _rmt_open (path, oflag, mode);
  816.  
  817.         return (fd == -1) ? -1 : (fd + REM_BIAS);
  818.     }
  819.     else
  820.     {
  821.         return (open (path, oflag, mode));
  822.     }
  823. }
  824.  
  825. /*
  826.  *    Test pathname for specified access.  Looks just like access(2)
  827.  *    to caller.
  828.  */
  829.  
  830. int rmtaccess (path, amode)
  831. char *path;
  832. int amode;
  833. {
  834.     if (remdev (path))
  835.     {
  836.         return (0);        /* Let /etc/rmt find out */
  837.     }
  838.     else
  839.     {
  840.         return (access (path, amode));
  841.     }
  842. }
  843.  
  844.  
  845. /*
  846.  *    Read from stream.  Looks just like read(2) to caller.
  847.  */
  848.   
  849. int rmtread (fildes, buf, nbyte)
  850. int fildes;
  851. char *buf;
  852. unsigned int nbyte;
  853. {
  854.     if (isrmt (fildes))
  855.     {
  856.         return (_rmt_read (fildes - REM_BIAS, buf, nbyte));
  857.     }
  858.     else
  859.     {
  860.         return (read (fildes, buf, nbyte));
  861.     }
  862. }
  863.  
  864.  
  865. /*
  866.  *    Write to stream.  Looks just like write(2) to caller.
  867.  */
  868.  
  869. int rmtwrite (fildes, buf, nbyte)
  870. int fildes;
  871. char *buf;
  872. unsigned int nbyte;
  873. {
  874.     if (isrmt (fildes))
  875.     {
  876.         return (_rmt_write (fildes - REM_BIAS, buf, nbyte));
  877.     }
  878.     else
  879.     {
  880.         return (write (fildes, buf, nbyte));
  881.     }
  882. }
  883.  
  884. /*
  885.  *    Perform lseek on file.  Looks just like lseek(2) to caller.
  886.  */
  887.  
  888. long rmtlseek (fildes, offset, whence)
  889. int fildes;
  890. long offset;
  891. int whence;
  892. {
  893.     if (isrmt (fildes))
  894.     {
  895.         return (_rmt_lseek (fildes - REM_BIAS, offset, whence));
  896.     }
  897.     else
  898.     {
  899.         return (lseek (fildes, offset, whence));
  900.     }
  901. }
  902.  
  903.  
  904. /*
  905.  *    Close a file.  Looks just like close(2) to caller.
  906.  */
  907.  
  908. int rmtclose (fildes)
  909. int fildes;
  910. {
  911.     if (isrmt (fildes))
  912.     {
  913.         return (_rmt_close (fildes - REM_BIAS));
  914.     }
  915.     else
  916.     {
  917.         return (close (fildes));
  918.     }
  919. }
  920.  
  921. /*
  922.  *    Do ioctl on file.  Looks just like ioctl(2) to caller.
  923.  */
  924.  
  925. int rmtioctl (fildes, request, arg)
  926. int fildes;
  927. unsigned long request;
  928. char *arg;
  929. {
  930.     if (isrmt (fildes))
  931.     {
  932. #ifdef RMTIOCTL
  933.         return (_rmt_ioctl (fildes - REM_BIAS, request, arg));
  934. #else
  935.         errno = EOPNOTSUPP;
  936.         return (-1);        /* For now  (fnf) */
  937. #endif
  938.     }
  939.     else
  940.     {
  941.         return (ioctl (fildes, request, arg));
  942.     }
  943. }
  944.  
  945.  
  946. /*
  947.  *    Duplicate an open file descriptor.  Looks just like dup(2)
  948.  *    to caller.
  949.  */
  950.  
  951. int rmtdup (fildes)
  952. int fildes;
  953. {
  954.     if (isrmt (fildes))
  955.     {
  956.         errno = EOPNOTSUPP;
  957.         return (-1);        /* For now (fnf) */
  958.     }
  959.     else
  960.     {
  961.         return (dup (fildes));
  962.     }
  963. }
  964.  
  965. /*
  966.  *    Get file status.  Looks just like fstat(2) to caller.
  967.  */
  968.  
  969. int rmtfstat (fildes, buf)
  970. int fildes;
  971. struct stat *buf;
  972. {
  973.     if (isrmt (fildes))
  974.     {
  975.         errno = EOPNOTSUPP;
  976.         return (-1);        /* For now (fnf) */
  977.     }
  978.     else
  979.     {
  980.         return (fstat (fildes, buf));
  981.     }
  982. }
  983.  
  984.  
  985. /*
  986.  *    Get file status.  Looks just like stat(2) to caller.
  987.  */
  988.  
  989. int rmtstat (path, buf)
  990. char *path;
  991. struct stat *buf;
  992. {
  993.     if (remdev (path))
  994.     {
  995.         errno = EOPNOTSUPP;
  996.         return (-1);        /* For now (fnf) */
  997.     }
  998.     else
  999.     {
  1000.         return (stat (path, buf));
  1001.     }
  1002. }
  1003.  
  1004.  
  1005.  
  1006. /*
  1007.  *    Create a file from scratch.  Looks just like creat(2) to the caller.
  1008.  */
  1009.  
  1010. #include <sys/file.h>        /* BSD DEPENDANT!!! */
  1011. /* #include <fcntl.h>        /* use this one for S5 with remote stuff */
  1012.  
  1013. int rmtcreat (path, mode)
  1014. char *path;
  1015. int mode;
  1016. {
  1017.     if (remdev (path))
  1018.     {
  1019.         return (rmtopen (path, 1 | O_CREAT, mode));
  1020.     }
  1021.     else
  1022.     {
  1023.         return (creat (path, mode));
  1024.     }
  1025. }
  1026.  
  1027. /*
  1028.  *    Isrmt. Let a programmer know he has a remote device.
  1029.  */
  1030.  
  1031. int isrmt (fd)
  1032. int fd;
  1033. {
  1034.     return (fd >= REM_BIAS);
  1035. }
  1036.  
  1037. /*
  1038.  *    Rmtfcntl. Do a remote fcntl operation.
  1039.  */
  1040.  
  1041. int rmtfcntl (fd, cmd, arg)
  1042. int fd, cmd, arg;
  1043. {
  1044.     if (isrmt (fd))
  1045.     {
  1046.         errno = EOPNOTSUPP;
  1047.         return (-1);
  1048.     }
  1049.     else
  1050.     {
  1051.         return (fcntl (fd, cmd, arg));
  1052.     }
  1053. }
  1054.  
  1055. /*
  1056.  *    Rmtisatty.  Do the isatty function.
  1057.  */
  1058.  
  1059. int rmtisatty (fd)
  1060. int fd;
  1061. {
  1062.     if (isrmt (fd))
  1063.         return (0);
  1064.     else
  1065.         return (isatty (fd));
  1066. }
  1067.  
  1068.  
  1069. /*
  1070.  *    Get file status, even if symlink.  Looks just like lstat(2) to caller.
  1071.  */
  1072.  
  1073. int rmtlstat (path, buf)
  1074. char *path;
  1075. struct stat *buf;
  1076. {
  1077.     if (remdev (path))
  1078.     {
  1079.         errno = EOPNOTSUPP;
  1080.         return (-1);        /* For now (fnf) */
  1081.     }
  1082.     else
  1083.     {
  1084.         return (lstat (path, buf));
  1085.     }
  1086. }
  1087. SHAR_EOF
  1088. fi
  1089. echo shar: "extracting 'rmtops.3'" '(5300 characters)'
  1090. if test -f 'rmtops.3'
  1091. then
  1092.     echo shar: "will not over-write existing file 'rmtops.3'"
  1093. else
  1094. cat << \SHAR_EOF > 'rmtops.3'
  1095. ...
  1096. ... $Header: rmtops.3,v 1.4 88/10/25 17:05:05 root Locked $
  1097. ... 
  1098. ... $Log:    rmtops.3,v $
  1099. ... Revision 1.4  88/10/25  17:05:05  root
  1100. ... Documented configuration options and added Dan Kegel to AUTHORS. ADR.
  1101. ... 
  1102. ... Revision 1.3  87/10/30  10:36:38  root
  1103. ... Some cleanup. 4.3 syntax is default, 4.2 is a compile time option.
  1104. ... 
  1105. ... Revision 1.2  86/10/09  16:38:02  root
  1106. ... Changed to reflect 4.3BSD rcp syntax and better rmt(8) capabilities. ADR.
  1107. ... 
  1108. ... Revision 1.1  86/10/09  16:18:47  root
  1109. ... Initial revision
  1110. ... 
  1111. ...
  1112. .TH RMTOPS 3 local
  1113. .SH NAME
  1114. rmtops \- access tape drives on remote machines
  1115. .SH SYNOPSIS
  1116. .nf
  1117. .ft B
  1118. #include <rmt.h>
  1119. #include <sys/stat.h>    /* MUST come after <rmt.h> */
  1120.  
  1121. int isrmt (fd)
  1122. int fd;
  1123.  
  1124. int rmtaccess (file, mode)
  1125. char *file;
  1126. int mode;
  1127.  
  1128. int rmtclose (fd)
  1129. int fd;
  1130.  
  1131. int rmtcreat (file, mode)
  1132. char *file;
  1133. int mode;
  1134.  
  1135. int rmtdup (fd)
  1136. int fd;
  1137.  
  1138. int rmtfcntl (fd, cmd, arg)
  1139. int fd, cmd, arg;
  1140.  
  1141. int rmtfstat (fd, buf)
  1142. int fd;
  1143. struct stat *buf;
  1144.  
  1145. int rmtioctl (fd, request, argp)
  1146. int fd, request;
  1147. char *argp;
  1148.  
  1149. int rmtisatty (fd)
  1150. int fd;
  1151.  
  1152. long rmtlseek (fd, offset, whence)
  1153. int fd, whence;
  1154. long offset;
  1155.  
  1156. int rmtlstat (file, buf)
  1157. char *file;
  1158. struct stat *buf;
  1159.  
  1160. int rmtopen (file, flags [, mode])
  1161. char *file;
  1162. int flags, mode;
  1163.  
  1164. int rmtread (fd, buf, nbytes)
  1165. int fd, nbytes;
  1166. char *buf;
  1167.  
  1168. int rmtstat (file, buf)
  1169. char *file;
  1170. struct stat *buf;
  1171.  
  1172. int rmtwrite (fd, buf, nbytes)
  1173. int fd, nbytes;
  1174. char *buf;
  1175. .fi
  1176. .ft R
  1177. .SH DESCRIPTION
  1178. .I Rmtops
  1179. provides a simple means of transparently accessing tape drives
  1180. on remote machines over the ethernet, via
  1181. .IR rsh (1)
  1182. and
  1183. .IR rmt (8).
  1184. These routines are used like their corresponding
  1185. system calls, but allow the user to open up a tape drive on a remote
  1186. system on which he or she has an account and the appropriate remote
  1187. permissions.
  1188. .PP
  1189. A remote tape drive file name has the form
  1190. .sp
  1191. .RS
  1192. .RI [ user @] system :/dev/???
  1193. .RE
  1194. .sp
  1195. where
  1196. .I system
  1197. is the remote system,
  1198. .I /dev/???
  1199. is the particular drive on the remote system (raw, blocked, rewinding,
  1200. non-rewinding, etc.), and the optional
  1201. .I user
  1202. is the login name to be used on the remote system, if different from
  1203. the current user's login name.
  1204. .PP
  1205. The library source code may be optionally compiled to recognize the
  1206. old, 4.2 BSD, remote syntax
  1207. .sp
  1208. .RS
  1209. .IR system [. user ]:/dev/???
  1210. .RE
  1211. .sp
  1212. By default, only the first form (introduced in 4.3 BSD) is recognized.
  1213. .PP
  1214. For transparency, the user should include the file
  1215. .IR <rmt.h> ,
  1216. which has the following defines in it:
  1217. .PP
  1218. .nf
  1219. #define access rmtaccess
  1220. #define close rmtclose
  1221. #define creat rmtcreat
  1222. #define dup rmtdup
  1223. #define fcntl rmtfcntl
  1224. #define fstat rmtfstat
  1225. #define ioctl rmtioctl
  1226. #define isatty rmtisatty
  1227. #define lseek rmtlseek
  1228. #define lstat rmtlstat
  1229. #define open rmtopen
  1230. #define read rmtread
  1231. #define stat rmtstat
  1232. #define write rmtwrite
  1233. .fi
  1234. .PP
  1235. This allows the programmer to use
  1236. .IR open ,
  1237. .IR close ,
  1238. .IR read ,
  1239. .IR write ,
  1240. etc. in their normal fashion, with the
  1241. .I rmtops
  1242. routines taking care of differentiating between local and remote files.
  1243. This file should be included
  1244. .I before
  1245. including the file
  1246. .IR <sys/stat.h> ,
  1247. since it redefines the identifier ``stat,'' which is used to declare
  1248. objects of type
  1249. .BR "struct stat" .
  1250. .PP
  1251. The routines differentiate between local and remote file descriptors by
  1252. adding a bias (currently 128) to the file descriptor of the pipe.
  1253. The programmer, if he or she must know if a file is remote, should use the
  1254. .I isrmt
  1255. function.
  1256. .SH FILES
  1257. .TP
  1258. .B /usr/lib/librmt.a
  1259. Contains the remote tape library.  To include the library with a program,
  1260. add the flag
  1261. .B \-lrmt
  1262. to the
  1263. .IR cc (1)
  1264. command line.
  1265. .SH SEE ALSO
  1266. .IR rcp (1),
  1267. .IR rsh (1),
  1268. .IR rmt (8),
  1269. and the appropriate system calls in section 2.
  1270. .SH DIAGNOSTICS
  1271. Several of these routines will return \-1 and set
  1272. .I errno
  1273. to EOPNOTSUPP, if they are given a remote file name or a file descriptor
  1274. on an open remote file (e.g.,
  1275. .IR rmtdup ).
  1276. .SH BUGS
  1277. See \s-1DIAGNOSTICS\s+1 above.  It is to be hoped that true remote file systems
  1278. will eventually appear, and eliminate the need for these routines.
  1279. .PP
  1280. There is no way to use remote tape drives with the
  1281. .IR stdio (3)
  1282. package, short of recompiling it entirely to use these routines.
  1283. .PP
  1284. The
  1285. .IR rmt (8)
  1286. protocol is not very capable.  In particular, it relies on
  1287. TCP/IP sockets for error free transmission, and does no data validation
  1288. of its own.
  1289. .SH CONFIGURATION OPTIONS
  1290. The library may be compiled to allow the use of 4.2 BSD style remote
  1291. file names. This is not recommended.
  1292. .PP
  1293. By default, the library opens two pipes to
  1294. .IR rsh (1).
  1295. It may optionally be compiled to use
  1296. .IR rexec (3),
  1297. instead. Doing so requires the use of a
  1298. .I .netrc
  1299. file in the user's home directory, or that the application designer
  1300. be willing to have
  1301. .I rexec
  1302. prompt the user for a login name and password on the remote host.
  1303. .SH AUTHORS
  1304. Jeff Lee (gatech!jeff) wrote the original routines for accessing
  1305. tape drives via
  1306. .IR rmt (8).
  1307. .PP
  1308. Fred Fish (unisoft!fnf) redid them into a general purpose library.
  1309. .PP
  1310. Arnold Robbins
  1311. (formerly gatech!arnold, now emory!arnold)
  1312. added the ability to specify a user
  1313. name on the remote system, the
  1314. .B <rmt.h>
  1315. include file, this man page,
  1316. cleaned up the library a little,
  1317. and made the appropriate changes for 4.3 BSD.
  1318. .PP
  1319. Dan Kegel (srs!dan) contributed the code to use
  1320. .IR rexec (3)
  1321. library routine.
  1322. SHAR_EOF
  1323. fi
  1324. exit 0
  1325. #    End of shell archive
  1326.  
  1327.